using System;
using System.Runtime.Serialization;
using System.Security.Cryptography;

namespace SharpObjects.Cryptography.Asymmetric
{
	[Serializable]
	public class RsaKey : ICryptoKey
	{
		protected RSAParameters m_params;

		public RsaKey()
		{
		}

		public RsaKey(RSAParameters parameters)
		{
			m_params = parameters;
		}

		public RSAParameters GetParameters()
		{
			return m_params;
		}

		public static implicit operator RSAParameters(RsaKey key)
		{
			return key.GetParameters();
		}

		//#region ISerializable Members

		public RsaKey(SerializationInfo info, StreamingContext context)
		{
			m_params.D = (byte [])info.GetValue("m_params.D", typeof(byte []));
			m_params.DP = (byte [])info.GetValue("m_params.DP", typeof(byte []));
			m_params.DQ = (byte [])info.GetValue("m_params.DQ", typeof(byte []));
			m_params.Exponent = (byte [])info.GetValue("m_params.Exponent", typeof(byte []));
			m_params.InverseQ = (byte [])info.GetValue("m_params.InverseQ", typeof(byte []));
			m_params.Modulus = (byte [])info.GetValue("m_params.Modulus", typeof(byte []));
			m_params.P = (byte [])info.GetValue("m_params.P", typeof(byte []));
			m_params.Q = (byte [])info.GetValue("m_params.Q", typeof(byte []));
		}

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("m_params.D",  m_params.D);
			info.AddValue("m_params.DP",  m_params.DP);
			info.AddValue("m_params.DQ",  m_params.DQ);
			info.AddValue("m_params.Exponent",  m_params.Exponent);
			info.AddValue("m_params.InverseQ",  m_params.InverseQ);
			info.AddValue("m_params.Modulus",  m_params.Modulus);
			info.AddValue("m_params.P",  m_params.P);
			info.AddValue("m_params.Q",  m_params.Q);

		}

		//#endregion

		public override bool Equals(object obj)
		{
			RsaKey key = (RsaKey)obj;

			if(!AreEqual(key.GetParameters().D, m_params.D))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().DP, m_params.DP))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().DQ, m_params.DQ))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().Exponent, m_params.Exponent))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().InverseQ, m_params.InverseQ))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().Modulus, m_params.Modulus))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().P, m_params.P))
			{
				return false;
			}

			if(!AreEqual(key.GetParameters().Q, m_params.Q))
			{
				return false;
			}

			return true;

		}

		protected bool AreEqual(byte [] arr1, byte [] arr2)
		{
			if(arr1 == null && arr2 == null)
			{
				return true;
			}

			if((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null))
			{
				return false;
			}

			if(arr1.Length != arr2.Length)
			{
				return false;
			}

			for(int k = 0; k < arr1.Length; k++)
			{
				if(arr1[k] != arr2[k])
				{
					return false;
				}
			}

			return true;
		}

		public static bool operator == (RsaKey key1, RsaKey key2)
		{
			return key1.Equals(key2);
		}

		public static bool operator != (RsaKey key1, RsaKey key2)
		{
			return ! key1.Equals(key2);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode ();
		}

	}
}
